
// Copyright (c) 2012, 2013 All Right Reserved, http://hpc.utp.edu.my
// Author: Nordin Zakaria nordinzakaria@gmail.com
// All rights reserved.

#include "AdjMatrix.h"

void AdjMatrix::zeros()
	{
        for (unsigned int i=0; i<N; i++)
             {
              memset(matrix[i], 0, N);
             }
	}

void AdjMatrix::clear()
	{
	if (N == 0)
	    return;

	for (unsigned int j=0; j<N; j++) {
	     delete [] matrix[j];
	     }
	delete []matrix;
	matrix = NULL;
	N = 0;
	}

void AdjMatrix::init(unsigned int N)
      {
        this->N = N;
        matrix = new unsigned char*[N];
        for (unsigned int i=0; i<N; i++)
             {
              matrix[i] = new unsigned char[N];
              memset(matrix[i], 0, N);
             }
      }

void AdjMatrix::rand()
       {
       for (unsigned int j=0; j<N; j++)
         {
          for (unsigned int i=0; i<N; i++)
           {
            unsigned char val = (unsigned int) Random::getGaussian(COMM_MEAN, COMM_SDV);
            set(i, j, val);
           }
          }
        }

void AdjMatrix::read(FILE *infile)
{
   for (unsigned int j=0; j<N; j++)
        {
	    fread(matrix[j],1,N,infile);
        }
}

void AdjMatrix::write(FILE *outfile)
{
  for (unsigned int j=0; j<N; j++)
      {
       fwrite(matrix[j], 1,N, outfile);
      }
}

void AdjMatrix::toText(string outtext)
{
  ofstream outfile(outtext.c_str());
  outfile << N << endl;
  for (unsigned int j=0; j<N; j++)
      {
	for (unsigned int i=0; i<N; i++) {
		double val = matrix[j][i] / 255.0;
		outfile << val << " ";
		}
	outfile << endl;
      }
  outfile.close();
}

void AdjMatrix::fromText(string intext)
{
  ifstream infile(intext.c_str());
  for (unsigned int j=0; j<N; j++)
      {
	for (unsigned int i=0; i<N; i++) {
		double val;
		infile >> val;
		matrix[j][i] = (unsigned char)floor(val * 255.0);
		}
      }
  infile.close();
}

ostream& operator<<(ostream& os, const AdjMatrix& obj)
        {
          for (unsigned int j=0; j<obj.N; j++) {
    	      os.write ((char*)obj.matrix[j], obj.N);
              }
          return os;
        }


istream& operator>>(istream& is, AdjMatrix& obj)
        {
          // read obj from stream
          for (unsigned int j=0; j<obj.N; j++)
              {
			  is.read((char*)obj.matrix[j], obj.N);
              }
          return is;
        }

AdjMatrix& AdjMatrix::operator=(const AdjMatrix& obj)
	{
	assert (N == obj.getN());
	for (unsigned int j=0; j<N; j++) 
	  for (unsigned int i=0; i<N; i++) 
			matrix[j][i] = obj.get(i, j);
	return *this;
	}

AdjMatrix& AdjMatrix::operator+=(const AdjMatrix& obj)
	{
	assert (N == obj.getN());
	for (unsigned int j=0; j<N; j++) 
	  for (unsigned int i=0; i<N; i++) 
			matrix[j][i] += obj.get(i, j);
	return *this;
	}

void AdjMatrix::extract(const vector<unsigned int> &workers, AdjMatrix& submat)
	{
	submat.init(workers.size());
	for (unsigned int i=0; i<workers.size(); i++)
		{
		unsigned int id_i = workers[i];
		for (unsigned int j=0; j<workers.size(); j++)
			{
			if (i == j) continue;

			unsigned int id_j = workers[j];
			unsigned char val = this->get(id_i, id_j);
			submat.set(i, j, val);
			}
		}
	}

void AdjMatrix::add(const vector<unsigned int> &workers, const AdjMatrix& submat)
	{
	for (unsigned int i=0; i<workers.size(); i++)
		{
		unsigned int id_i = workers[i];
		for (unsigned int j=0; j<workers.size(); j++)
			{
			if (i == j) continue;

			unsigned int id_j = workers[j];
			unsigned char val = this->get(id_i, id_j);
			unsigned char incoming_val = submat.get(i, j);
			this->set(id_i, id_j, val+incoming_val);
			}
		}
	}


